﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using Net.Chirash.Twitter.TwitterDatabase;

namespace Net.Chirash.Twitter.TwitterClient.DBSyncronize
{
    public abstract class CachingSynchronizer
        : INotifyPropertyChanged
    {
        protected List<TaskBase> TaskCollection { get; private set; }

        public CachingSynchronizer()
        {
            this.TaskCollection = new List<TaskBase>();

            this.RefreshedTask = 1.0;
            this.TobeRefreshedTask = 2.0;
        }

        #region task manipulation

        public void AddTask(TaskBase task)
        {
            if (ExistTask(task))
                throw new ArgumentException("すでにTaskは追加されています。重複する名前でないか確認してください");
            TaskCollection.Add(task);
        }

        public void AddTaskIgnoringException(TaskBase task)
        {
            if (!ExistTask(task))
                TaskCollection.Add(task);
        }

        public TaskBase GetTask(string taskname)
        {
            return TaskCollection.Find((item) => item.TaskName == taskname);
        }

        public bool ExistTask(TaskBase task)
        {
            return TaskCollection.Exists((item) => item == task);
        }

        public bool ExistTask(string taskname)
        {
            return TaskCollection.Exists((item) => item.TaskName == taskname);
        }

        public void DeleteTask(TaskBase task)
        {
            TaskCollection.Remove(task);
        }

        #endregion

        #region protected helper functions

        protected void NotifyTasks(object arg)
        {
            var freezedList = this.TaskCollection.ToArray();
            this.TobeRefreshedTask = (double)freezedList.Count();
            this.RefreshedTask = 1.0;

            foreach (var task in freezedList)
            {
                if (!task.IsObserved)
                    DeleteTask(task);
                else
                {
                    if (TaskCollection.Contains(task))
                        task.DoTask(arg);
                }
                RefreshedTask++;
            }
        }

        #endregion

        #region public bool IsRefreshing { get; protected set; }
        private bool _IsRefreshing;
        public bool IsRefreshing
        {
            get { return _IsRefreshing; }
            protected set { _IsRefreshing = value; OnPropertyChanged("IsRefreshingColumn"); }
        }
        #endregion
        #region public double TobeRefreshedTask { get; protected set; }
        private double _TobeRefreshedTask;
        public double TobeRefreshedTask
        {
            get { return _TobeRefreshedTask; }
            protected set { _TobeRefreshedTask = value; OnPropertyChanged("TobeRefreshedTask"); }
        }
        #endregion
        #region public double RefreshedTask { get; protected set; }
        private double _RefreshedTask;
        public double RefreshedTask
        {
            get { return _RefreshedTask; }
            protected set { _RefreshedTask = value; OnPropertyChanged("RefreshedTask"); }
        }
        #endregion

        #region Implementation of INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion

    }

    public class CachingObservingSynchronizer
        : CachingSynchronizer, System.IObserver<TwitterMessage>
    {
        public void OnCompleted()
        {
            
        }

        public void OnError(Exception error)
        {
            
        }

        public void OnNext(TwitterMessage value)
        {
            if (this.IsRefreshing)
                return;
            else
                this.IsRefreshing = true;
            try
            {
                switch (value.MessageType)
                {
                    case TwitterMessageType.Status:
                    case TwitterMessageType.RetweetedStatus:
                        NotifyTasks(new Status[] { value.Data as Status });
                        break;
                    case TwitterMessageType.DirectMessage:
                        NotifyTasks(new User[] { value.Data as User });
                        break;
                    case TwitterMessageType.Event:
                        NotifyTasks(new TwitterEvent[] { value.Data as TwitterEvent });
                        break;
                    case TwitterMessageType.DeleteStatus:
                        NotifyTasks(new DeletedData[] { value.Data as DeletedData });
                        break;
                }
                //NotifyTasks(new TwitterData[] {value.Data});
            }
            finally
            {
                this.IsRefreshing = false;
            }
        }
    }

    public class CachingTimerSynchronizer
        : CachingSynchronizer
    {
        private Timer timer;

        public event EventHandler TimerStarted;
        public event EventHandler TimerFinished;

        public CachingTimerSynchronizer()
            : base()
        {
        }

        public void Start(int intervalMilisecond)
        {
            Stop();
            this.timer = new Timer(new TimerCallback(timerCallBackMethod), null, 0, intervalMilisecond);
        }

        public void Stop()
        {
            if (this.timer != null)
                this.timer.Dispose();
        }

        private void timerCallBackMethod(object state)
        {
            if (this.IsRefreshing)
                return;
            else
                this.IsRefreshing = true;

            try
            {
                OnTimerStarted();

                this.NotifyTasks(null);
            }
            finally
            {
                OnTimerFinished();
                this.IsRefreshing = false;
            }
        }

        protected void OnTimerStarted()
        {
            if (this.TimerStarted != null)
                TimerStarted(this, new EventArgs());
        }

        protected void OnTimerFinished()
        {
            if (this.TimerFinished != null)
                TimerFinished(this, new EventArgs());
        }

    }
}
